import math
from OpenGL.GL import *
from OpenGL.GLU import *
from gameobjects.matrix44 import Matrix44
from gameobjects.angle3 import Angle3
from gameobjects.vector3 import Vector3
from phuce.plane import Plane
from phuce.physics import Orientation
from phuce import settings


class View(object):

  def __init__(self, fov=None, orientation=None):
    self.fov = fov or 90
    self.frustum = [Plane() for i in range(4)]
    self.mins = Vector3()
    self.maxs = Vector3()
    self.orientation = orientation or Orientation()
    self.update_frustum()

  def apply(self):
    self.update_frustum()
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(float(self.fov_x), float(settings.width) / float(settings.height), 0.1, 4096.0)
    glMatrixMode(GL_MODELVIEW)
    m = self.orientation.ypr_matrix.copy()
    m.translate = self.orientation.xyz
    glLoadMatrixf(m.get_inverse().to_opengl())

  def get_fov(self):
    return self.fov_x
  def set_fov(self, fov):
    self.fov_x = float(fov)
    self.fov_y = math.atan2(settings.height, settings.width / math.tan(self.fov_x / 360 * math.pi)) * 360 / math.pi
  fov = property(get_fov, set_fov)

  def update_frustum(self):
    angles = [fov / 180.0 * math.pi * 0.5 for fov in (self.fov_x, self.fov_y)]
    forward = self.orientation.forward
    for i, frustum in enumerate(self.frustum):
      j = i / 2
      frustum.normal = forward * math.sin(angles[j])
      frustum.normal += self.orientation.ypr_matrix.get_row_vec3(j) * (math.cos(angles[j]) * (i % 2 and -1 or 1))
      frustum.distance = frustum.normal.dot(self.orientation.xyz)
      frustum.type = None
      self.frustum[i] = frustum
